﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace RMS.Utils.EventAggregators
{
    public abstract class BaseEvent
    {
        // Fields
        private readonly List<IEventSubscription> _subscriptions = new List<IEventSubscription>();

        // Methods
        protected BaseEvent()
        {
        }

        public virtual bool Contains(SubscriptionToken token)
        {
            Func<IEventSubscription, bool> func = null;
            lock (this._subscriptions)
            {
                return (Enumerable.FirstOrDefault<IEventSubscription>(this._subscriptions, func) != null);
            }
        }

        private List<Action<object[]>> PruneAndReturnStrategies()
        {
            List<Action<object[]>> list = new List<Action<object[]>>();
            lock (this._subscriptions)
            {
                for (int i = this._subscriptions.Count - 1; i >= 0; i--)
                {
                    Action<object[]> executionStrategy = this._subscriptions[i].GetExecutionStrategy();
                    if (executionStrategy == null)
                    {
                        this._subscriptions.RemoveAt(i);
                    }
                    else
                    {
                        list.Add(executionStrategy);
                    }
                }
            }
            return list;
        }

        protected virtual void Publish(params object[] arguments)
        {
            foreach (Action<object[]> action in this.PruneAndReturnStrategies())
            {
                action(arguments);
            }
        }

        protected virtual SubscriptionToken Subscribe(IEventSubscription eventSubscription)
        {
            eventSubscription.SubscriptionToken = new SubscriptionToken();
            lock (this._subscriptions)
            {
                this._subscriptions.Add(eventSubscription);
            }
            return eventSubscription.SubscriptionToken;
        }

        public virtual void Unsubscribe(SubscriptionToken token)
        {
            lock (_subscriptions)
            {
                IEventSubscription subscription = _subscriptions.FirstOrDefault(evt => evt.SubscriptionToken == token);

                if (subscription != null)
                {
                    _subscriptions.Remove(subscription);
                }
            }
        }

        // Properties
        protected ICollection<IEventSubscription> Subscriptions
        {
            [DebuggerStepThrough]
            get
            {
                return this._subscriptions;
            }
        }
    }
}
